from checkers import strategy
from checkers import utils
import random
from time import sleep
import cmd

class MoveCmd(cmd.Cmd, object):

    _valid_moves = []
    _move = None
    prompt = 'Your move? (press <TAB> for available options or ? for help)\n'

    def set_moves(self, moves):
        self._move = None
        self._valid_moves = moves

    def get_move(self):
        return self._move

    def preloop(self):
        super(MoveCmd, self).preloop()
        try:
            import readline
            self.old_delims = readline.get_completer_delims()
            self.delims = filter(lambda d: d not in ('-',), self.old_delims)
            readline.set_completer_delims(self.delims)
        except ImportError:
            pass

    def postloop(self):
        super(MoveCmd, self).postloop()
        try:
            import readline
            readline.set_completer_delims(self.old_delims)
        except ImportError:
            pass

    def complete_move(self, text, line, begidx, endidx):
        return [i for i in self._valid_moves if i.startswith(text)]

    def completenames(self, text, line, begidx, endidx):
        return self.complete_move(text, line, begidx, endidx) + ['help', 'move']

    completedefault = completenames

    def help_move(self):
        doc = """move <start-end>

        Executes the choosen move, if its a valid move.
        """
        print doc

    def do_move(self, move):
        if move in self._valid_moves:
            self._move = move
            return True
        return False

    def onecmd(self, line):
        if (not line.startswith('move')
            and not line.startswith('help')):
            line = 'move ' + line
        r = super(MoveCmd, self).onecmd(line)
        return r

mover = MoveCmd()

_registry = {}

def register(name, player):
    _registry[name] = player

def get_player(name, default=None):
    return _registry.get(name, default)

def stringify_moves(moves):
    res = []
    for move in moves:
        start, end, steps, taken = move
        res.append('%s%s-%s%s' % (start[0], start[1], end[0], end[1]))
    return res

def display_moves(moves):
    res = stringify_moves(moves)
    for move in res:
        print move

def query_player(game, state):
    """Make a move by querying standard input.
    """
    move = None
    mover.set_moves(stringify_moves(state.moves))
    while move is None:
        mover.cmdloop()
        move = mover.get_move()
        move = '%s:%s' % (state.to_move, move)
        try:
            move = utils.parse_move(move)
        except ValueError:
            move = None
            continue
        player = move[0]
        move = move[1:]
        valid_moves = state.moves
        move = find_move(valid_moves, move)
    return move

register('query', query_player)

def random_player(game, state):
    """Choose a move at random.
    """
    return random.choice(game.legal_moves(state))

register('random', random_player)

def alphabeta_player(game, state, depth=2):
    """Choose a move using alphabeta search with a cuttof
    at the specified depth.
    """
    return strategy.alphabeta_search(state, game, depth)

register('alpha-beta', alphabeta_player)

def find_move(moves, move):
    for m in moves:
        if m[:2] == move[:2]:
            return m
    # Couldn't find matching steps
    for m in moves:
        if m[:1] == move[:1]:
            return m
    return None

def file_player(game, state, fp=None, ask=False, out=None):
    """Read a move from a file.
    """
    if ask:
        raw_input('Press a key to play:')
    def write(msg, out=out):
        if out is not None:
            out.write(msg)
            out.flush()
    write('Waiting for the other player to move ')
    while True:
        f = open(fp, 'r')
        lines = f.readlines()
        f.close()
        move = lines[-1]
        move = utils.parse_move(move)
        player = move[0]
        if str(state.to_move) == player:
            break
        write('.')
        sleep(1)
    write('\n\n')
    move = move[1:]
    valid_moves = state.moves
    move = find_move(valid_moves, move)
    return move

register('file', file_player)

def wx_player(game, state, ui):
    return ui.get_move(game, state)

class Player:

    def __init__(self, strategy, loggers=None, **kw):
        self.strategy = strategy
        self.kw = kw
        if loggers is None:
            loggers = []
        self.loggers = loggers

    def __call__(self, game, state, **kw):
        kw.update(self.kw)
        kw['game'] = game
        kw['state'] = state
        game.display(state)
        move = self.strategy(**kw)
        for log in self.loggers:
            log(self, game, state, move)
        return move
